package top.tangyh.lamp.care.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tangyh.basic.cache.lock.RedisDistributedLock;
import top.tangyh.basic.exception.BizException;
import top.tangyh.lamp.care.entity.*;
import top.tangyh.lamp.care.mapper.*;
import top.tangyh.lamp.care.service.BCareIsbarAPgService;
import top.tangyh.lamp.care.service.BCareIsbarHandoverService;
import top.tangyh.basic.base.service.impl.SuperServiceImpl;
import top.tangyh.lamp.care.manager.BCareIsbarHandoverManager;
import top.tangyh.lamp.care.vo.query.CareISBARQueryInVO;
import top.tangyh.lamp.care.vo.result.*;
import top.tangyh.lamp.care.vo.save.BCareIsbarHandoverDetailSaveVO;
import top.tangyh.lamp.care.vo.save.BCareIsbarHandoverSaveVO;
import top.tangyh.lamp.care.vo.save.CareISBARAPgInVO;
import top.tangyh.lamp.care.vo.save.CareISBARHandoverInVO;
import top.tangyh.lamp.care.vo.update.BCareIsbarHandoverUpdateVO;
import top.tangyh.lamp.care.vo.query.BCareIsbarHandoverPageQuery;
import top.tangyh.lamp.common.constant.EventEnum;
import top.tangyh.lamp.common.constant.YzTypeEnum;
import top.tangyh.lamp.common.properties.SystemProperties;
import top.tangyh.lamp.common.utils.ConvertUtil;
import top.tangyh.lamp.common.utils.IcuDateUtils;
import top.tangyh.lamp.common.utils.PDateUtils;
import top.tangyh.lamp.common.utils.YDateUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * ISBAR护理交班表
 * </p>
 *
 * @author zqb
 * @date 2024-08-12 10:28:25
 * @create [2024-08-12 10:28:25] [zqb] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class BCareIsbarHandoverServiceImpl extends SuperServiceImpl<BCareIsbarHandoverManager, Long, BCareIsbarHandover> implements BCareIsbarHandoverService {


    private final BCareIsbarHandoverMapper bCareIsbarHandoverMapper;

    private final BCareIsbarAPgMapper bCareIsbarAPgMapper;

    private final BCareIsbarHandoverDetailMapper bCareIsbarHandoverDetailMapper;

    private final BPatientMapper bPatientMapper;

    @Autowired
    protected SystemProperties systemProperties;

    private final BHl7EventMapper bHl7EventMapper;

    private final BHl7RkZdDetailMapper bHl7RkZdDetailMapper;

    private final BHl7YzMapper bHl7YzMapper;

    private final BIoRecordMapper bIoRecordMapper;

    private final BPgRecordMapper bPgRecordMapper;

    private final BCarePgVteMapper bCarePgVteMapper;

    private final BHl7MoveDetailMapper bHl7MoveDetailMapper;

    private final BPatEventMapper bPatEventMapper;

//    @Resource
//    private RedissonClient redissonClient;

    private final BCareIsbarAPgService bCareIsbarAPgService;


    private final String ISBAR_LOCK_PRE = "redis:lock:isbar:";

    @Resource
    private  RedisDistributedLock redisDistributedLock;

    @Override
    public BCareIsbarHandoverResultVO queryLast(Long receiveDate) {
        //1、根据日期查找是否有记录 有记录优先返回
        Date date = new Date(receiveDate);
        long receiveStartOfDay = DateUtil.beginOfDay(date).getTime();
        long endOfDay = DateUtil.endOfDay(date).getTime();
        String startDate = DateUtil.formatDateTime(DateUtil.date(receiveStartOfDay));
        String endDate = DateUtil.formatDateTime(DateUtil.date(endOfDay));
        BCareIsbarHandover recordPo = bCareIsbarHandoverMapper.selectOneByTime(startDate, endDate);
        if (recordPo != null) {
            return convertToOutVo(recordPo);
        }

        //2、如果没有找到记录，则由程序自动生成结果
        BCareIsbarHandoverResultVO outVO = new BCareIsbarHandoverResultVO();

        long currentTime = System.currentTimeMillis();
        long currentBeginOfDay = DateUtil.beginOfDay(new Date(currentTime)).getTime();
        // 过去日期的情况下只需要计算 除 在院病人数据和总人数的其他统计
        long startTime;
        long endTime;

        // 明细数据 根据在院的病人信息生成
        List<PatientInfoOutVO> yxPatientList = bPatientMapper.selectListByDept(systemProperties.getIcuCode());
        Set<String> hospitalNumSet = yxPatientList.stream().map(PatientInfoOutVO::getHospitalNumber).filter(StrUtil::isNotBlank).collect(Collectors.toSet());

        //获取入科时间集合
        Map<String, List<BHl7Event>> rkmap = bHl7EventMapper.selectByEventTypeHospitalNumbers(EventEnum.RK.getEventType(), hospitalNumSet)
                .stream().collect(Collectors.groupingBy(BHl7Event::getHospitalNumber));
        //获取出科时间集合
        Map<String, List<BHl7Event>> ckmap = bHl7EventMapper.selectByEventTypeHospitalNumbers(EventEnum.CK.getEventType(), hospitalNumSet)
                .stream().collect(Collectors.groupingBy(BHl7Event::getHospitalNumber));
        Integer patientcount;
        if (CollectionUtil.isEmpty(yxPatientList)) {
            patientcount = 0;
        } else {
            patientcount = yxPatientList.size();

        }
        if (receiveDate < currentBeginOfDay) {
            startTime = IcuDateUtils.getTimestampByHour(receiveStartOfDay, 8);
            endTime = IcuDateUtils.getTimestampByHour(receiveStartOfDay, 24);
        } else {
            // 计算当前时间是当天的8点前还是后，需要计算出统计的时间区间 当天的八点
            long dayOfEight = IcuDateUtils.getTimestampByHour(currentBeginOfDay, 8);
            //当前时间在当天的8点之前算前一天的交班
            if (currentTime <= dayOfEight) {
                startTime = IcuDateUtils.getTimestampBeforeHour(dayOfEight, 24);
                endTime = dayOfEight;
            } else {
                //当前时间在当天的8点之后算今天的交班
                startTime = dayOfEight;
                endTime = currentTime;
            }
            //只处理当天的数据 --> 在院病人数据和总人数
            //总人数只计算当前时间点在院人数，过去时间统计
            outVO.setTotalCount(patientcount);
            //入科诊断
            Map<String, List<BHl7RkZdDetail>> rkZdMap = bHl7RkZdDetailMapper.selectListByHospitalNumList(hospitalNumSet).stream().collect(Collectors.groupingBy(BHl7RkZdDetail::getHospitalNumber));
            //在院期间所有手术
            Map<String, List<BHl7Yz>> operaMap = bHl7YzMapper.selectOperasByHospNumListAndType(hospitalNumSet, YzTypeEnum.SHOUSHU.getTypeCode()).stream().collect(Collectors.groupingBy(BHl7Yz::getHospitalNumber));

            //a班a评估出入量相关
            Map<String, List<IoCodeDetailVO>> ioInA = bIoRecordMapper.queryIoStatisticsListAll("crl-in", hospitalNumSet,
                    new Date(startTime), YDateUtils.addDateHours(new Date(startTime - 1000), 8)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioInSumA = bIoRecordMapper.queryIoStatisticsSumAll("crl-in", hospitalNumSet,
                    new Date(startTime), YDateUtils.addDateHours(new Date(startTime - 1000), 8)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutA = bIoRecordMapper.queryIoStatisticsListAll("crl-out", hospitalNumSet,
                    new Date(startTime), YDateUtils.addDateHours(new Date(startTime - 1000), 8)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutSumA = bIoRecordMapper.queryIoStatisticsSumAll("crl-out", hospitalNumSet,
                    new Date(startTime), YDateUtils.addDateHours(new Date(startTime - 1000), 8)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));


            //p班a评估出入量相关
            Map<String, List<IoCodeDetailVO>> ioInP = bIoRecordMapper.queryIoStatisticsListAll("crl-in", hospitalNumSet,
                            YDateUtils.addDateHours(new Date(startTime), 8), YDateUtils.addDateHours(new Date(startTime - 1000), 16)).
                    stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioInSumP = bIoRecordMapper.queryIoStatisticsSumAll("crl-in", hospitalNumSet,
                            YDateUtils.addDateHours(new Date(startTime), 8), YDateUtils.addDateHours(new Date(startTime - 1000), 16)).
                    stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutP = bIoRecordMapper.queryIoStatisticsListAll("crl-out", hospitalNumSet,
                            YDateUtils.addDateHours(new Date(startTime), 8), YDateUtils.addDateHours(new Date(startTime - 1000), 16)).
                    stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutSumP = bIoRecordMapper.queryIoStatisticsSumAll("crl-out", hospitalNumSet,
                            YDateUtils.addDateHours(new Date(startTime), 8), YDateUtils.addDateHours(new Date(startTime - 1000), 16)).
                    stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            //n班a评估出入量相关
            Map<String, List<IoCodeDetailVO>> ioInN = bIoRecordMapper.queryIoStatisticsListAll("crl-in", hospitalNumSet,
                    new Date(startTime), new Date(endTime - 1000)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioInSumN = bIoRecordMapper.queryIoStatisticsSumAll("crl-in", hospitalNumSet,
                    new Date(startTime), new Date(endTime - 1000)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutN = bIoRecordMapper.queryIoStatisticsListAll("crl-out", hospitalNumSet,
                    new Date(startTime), new Date(endTime - 1000)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            Map<String, List<IoCodeDetailVO>> ioOutSumN = bIoRecordMapper.queryIoStatisticsSumAll("crl-out", hospitalNumSet,
                    new Date(startTime), new Date(endTime - 1000)).stream().collect(Collectors.groupingBy(IoCodeDetailVO::getHospitalNumber));

            //特别提醒
            //glasgow
            Map<String, List<IsbarPgRecordDTO>> glasgow = bPgRecordMapper.getLatestPgRecordAll("pgpf_glasgow", hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //跌倒/坠床评分
            Map<String, List<IsbarPgRecordDTO>> fall = bCarePgVteMapper.getLatestPgVTERecordAll(4, hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //Braden评分
            Map<String, List<IsbarPgRecordDTO>> braden = bPgRecordMapper.getLatestPgRecordAll("pgpf_braden", hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //iss评分
            Map<String, List<IsbarPgRecordDTO>> iss = bPgRecordMapper.getLatestPgRecordAll("pgpf_iss", hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //APACHII评分
            Map<String, List<IsbarPgRecordDTO>> apachii = bCarePgVteMapper.getLatestPgVTERecordAll(3, hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //SOFA评分
            Map<String, List<IsbarPgRecordDTO>> sofa = bPgRecordMapper.getLatestPgRecordAll("pgpf_sofa", hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));
            //VTE评分
            Map<String, List<IsbarPgRecordDTO>> vte = bCarePgVteMapper.getLatestPgVTERecordAll(1, hospitalNumSet, new Date(startTime), new Date(endTime - 1000))
                    .stream().collect(Collectors.groupingBy(IsbarPgRecordDTO::getHospitalNumber));


            List<CareISBARHandoverDetailOutVO> detailOutList = yxPatientList.stream().map(CareISBARHandoverDetailOutVO::new).peek(detailOutVO -> {
                // 入科诊断


                List<BHl7RkZdDetail> rkZdList = rkZdMap.get(detailOutVO.getHospitalNumber());
                if (CollectionUtil.isNotEmpty(rkZdList)) {
                    StringBuilder builder = new StringBuilder();
                    for (int i = 0; i < rkZdList.size(); i++) {
                        builder.append(i + 1).append("、").append(rkZdList.get(i).getZdName()).append("\r\n");
                    }
                    detailOutVO.setsContext(builder.toString());
                }

                // 近期手术
                List<BHl7Yz> yzList = operaMap.get(detailOutVO.getHospitalNumber());
                if (CollectionUtil.isNotEmpty(yzList)) {
                    StringBuilder operaBuilder = new StringBuilder();
                    for (int i = 0; i < yzList.size(); i++) {
                        operaBuilder.append(i + 1).append("、").append(yzList.get(i).getOrderName()).append("\r\n");
                    }
                    detailOutVO.setbContext(operaBuilder.toString());
                }

                //入科时间 不存在则设为apn班开始时间
                LocalDateTime rktime = PDateUtils.getDateTimeOfTimestamp(startTime);
                List<BHl7Event> rks = rkmap.get(detailOutVO.getHospitalNumber());
                if (CollectionUtil.isNotEmpty(rks)) {
                    rktime = rks.get(0).getEventTime();
                }
                //出科时间 不存在则设为apn班结束时间
                LocalDateTime cktime = PDateUtils.getDateTimeOfTimestamp(endTime);
                List<BHl7Event> cks = ckmap.get(detailOutVO.getHospitalNumber());
                if (CollectionUtil.isNotEmpty(cks)) {
                    cktime = rks.get(0).getEventTime();
                }

                // a评估出入量
                List<CareISBARAPgOutVO> yxCareISBARAPgOutVOS = new ArrayList<>();
                CareISBARAPgOutVO workplanA = new CareISBARAPgOutVO();
                workplanA.setWorkName("A班");
                if (setApgIoTime(new Date(startTime), new Date(endTime), PDateUtils.LocalDateTimeToDate(rktime), PDateUtils.LocalDateTimeToDate(cktime), workplanA, 1)) {
                    IsbarIOOutVo isbarIOOutVoA = new IsbarIOOutVo();
                    isbarIOOutVoA.setInValue("0");
                    if (ioInSumA.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoA.setInValue(ioInSumA.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    isbarIOOutVoA.setOutValue("0");
                    if (ioOutSumA.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoA.setOutValue(ioOutSumA.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    if (ioInA.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoA.setInList(ioInA.get(detailOutVO.getHospitalNumber()));
                    }
                    if (ioOutA.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoA.setOutList(ioOutA.get(detailOutVO.getHospitalNumber()));
                    }
                    addInOutString(workplanA, isbarIOOutVoA);
                }
                yxCareISBARAPgOutVOS.add(workplanA);
                CareISBARAPgOutVO workplanP = new CareISBARAPgOutVO();
                workplanP.setWorkName("P班");
                if (setApgIoTime(new Date(startTime), new Date(endTime), PDateUtils.LocalDateTimeToDate(rktime), PDateUtils.LocalDateTimeToDate(cktime), workplanP, 2)) {
                    IsbarIOOutVo isbarIOOutVoP = new IsbarIOOutVo();
                    isbarIOOutVoP.setInValue("0");
                    if (ioInSumP.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoP.setInValue(ioInSumP.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    isbarIOOutVoP.setOutValue("0");
                    if (ioOutSumP.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoP.setOutValue(ioOutSumP.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    if (ioInP.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoP.setInList(ioInP.get(detailOutVO.getHospitalNumber()));
                    }
                    if (ioOutP.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoP.setOutList(ioOutP.get(detailOutVO.getHospitalNumber()));
                    }
                    addInOutString(workplanP, isbarIOOutVoP);
                }
                yxCareISBARAPgOutVOS.add(workplanP);
                CareISBARAPgOutVO workplanN = new CareISBARAPgOutVO();
                workplanN.setWorkName("N班");
                if (setApgIoTime(new Date(startTime), new Date(endTime), PDateUtils.LocalDateTimeToDate(rktime), PDateUtils.LocalDateTimeToDate(cktime), workplanN, 3)) {
                    IsbarIOOutVo isbarIOOutVoN = new IsbarIOOutVo();
                    isbarIOOutVoN.setInValue("0");
                    if (ioInSumN.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoN.setInValue(ioInSumN.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    isbarIOOutVoN.setOutValue("0");
                    if (ioOutSumN.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoN.setOutValue(ioOutSumN.get(detailOutVO.getHospitalNumber()).get(0).getIoValue());
                    }
                    if (ioInN.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoN.setInList(ioInN.get(detailOutVO.getHospitalNumber()));
                    }
                    if (ioOutN.containsKey(detailOutVO.getHospitalNumber())) {
                        isbarIOOutVoN.setOutList(ioOutN.get(detailOutVO.getHospitalNumber()));
                    }
                    addInOutString(workplanN, isbarIOOutVoN);
                }
                yxCareISBARAPgOutVOS.add(workplanN);
                detailOutVO.setJiaoBanList(yxCareISBARAPgOutVOS);
                // 特别提醒
                StringBuilder operaBuilder = new StringBuilder();
                //glassgow评分
                List<IsbarPgRecordDTO> pglasgow = glasgow.get(detailOutVO.getHospitalNumber());
                addListRemindWord(pglasgow, operaBuilder, 0);
                //跌倒/坠床评分
                List<IsbarPgRecordDTO> pfall = fall.get(detailOutVO.getHospitalNumber());
                addListRemindWord(pfall, operaBuilder, 1);
                //barden评分
                List<IsbarPgRecordDTO> pbraden = braden.get(detailOutVO.getHospitalNumber());
                addListRemindWord(pbraden, operaBuilder, 2);
                //ISS评分
                List<IsbarPgRecordDTO> piss = iss.get(detailOutVO.getHospitalNumber());
                addListRemindWord(piss, operaBuilder, 3);
                //APACHII评分
                List<IsbarPgRecordDTO> papachii = apachii.get(detailOutVO.getHospitalNumber());
                addListRemindWord(papachii, operaBuilder, 3);
                //SOFA评分
                List<IsbarPgRecordDTO> psofa = sofa.get(detailOutVO.getHospitalNumber());
                addListRemindWord(psofa, operaBuilder, 3);
                //vte评分
                List<IsbarPgRecordDTO> pvte = vte.get(detailOutVO.getHospitalNumber());
                addListRemindWord(pvte, operaBuilder, 4);
                detailOutVO.setSpecialRemind(operaBuilder.toString());
            }).collect(Collectors.toList());
            outVO.setDetailList(detailOutList);
        }

        String start = DateUtil.formatDateTime(new Date(startTime));
        String end = DateUtil.formatDateTime(new Date(endTime));
        // 统计计算
        // 入院统计 入科的人数
        int ryCount = patientcount;
        // 出院统计 统计出院事件
        int cyCount = bHl7EventMapper.countCy(start, end, systemProperties.getIcuCode());
        // 转入统计
        int zrCount = bHl7MoveDetailMapper.countZhuanRu(start, end, systemProperties.getIcuCode());
        // 转出统计
        int zcCount = bHl7MoveDetailMapper.countZhuanChu(start, end, systemProperties.getIcuCode());
        // 死亡统计
        int dieCount = bPatEventMapper.countDie(new Date(startTime), new Date(endTime));
        // 手术统计
        int operCount = (int) bHl7YzMapper.selectOperasByHospNumListAndTypeAndTime(hospitalNumSet, YzTypeEnum.SHOUSHU.getTypeCode(), new Date(startTime), new Date(endTime));

        outVO.setOperaCount(operCount);
        outVO.setRyCount(ryCount);
        outVO.setCyCount(cyCount);
        outVO.setZrCount(zrCount);
        outVO.setZcCount(zcCount);
        outVO.setDieCount(dieCount);
        return outVO;
    }

    /**
     * ISBAR交班实体类转outVo
     *
     * @param recordPo
     * @return
     */
    private BCareIsbarHandoverResultVO convertToOutVo(BCareIsbarHandover recordPo) {
        BCareIsbarHandoverResultVO handoverOutVO = ConvertUtil.convert(recordPo, BCareIsbarHandoverResultVO.class);
        //根据记录id查找明细
        List<BCareIsbarHandoverDetail> detailList = bCareIsbarHandoverDetailMapper.selectListByRecordId(recordPo.getId());
        //根据明细id查询出A评估和班次数据
        List<Long> detailIdList = detailList.stream().map(BCareIsbarHandoverDetail::getId).collect(Collectors.toList());
        //根据明细id查找交班的记录 key=detailId v=list
        Map<Long, List<CareISBARAPgOutVO>> jiaoBanMap = bCareIsbarAPgMapper.selectListByDetailIds(detailIdList).stream().map(CareISBARAPgOutVO::new).collect(Collectors.groupingBy(CareISBARAPgOutVO::getDetailId));
        //封装明细
        List<CareISBARHandoverDetailOutVO> detailOutList = detailList.stream().map(detailPO -> {
            CareISBARHandoverDetailOutVO outVO = ConvertUtil.convert(detailPO, CareISBARHandoverDetailOutVO.class);
            // new BCareIsbarHandoverDetailResultVO(detailPO);
            outVO.setJiaoBanList(jiaoBanMap.get(detailPO.getId()));
            return outVO;
        }).collect(Collectors.toList());

        handoverOutVO.setDetailList(detailOutList);
        return handoverOutVO;
    }

    /**
     * 设置出入量统计时长
     *
     * @param startTime apn开始时间
     * @param endTime   apn结束时间
     * @param rk        入科时间
     * @param ck        出科时间
     * @param workplan  A评估和交班明细回参类
     * @param type      1 a班,2 p班,3 n班
     * @return true 在排班时间内，false 不在排班时间内
     */
    public boolean setApgIoTime(Date startTime, Date endTime, Date rk, Date ck, CareISBARAPgOutVO workplan, int type) {
        Date start;
        Date end;
        if (ck.before(startTime) || rk.after(endTime)) {
            return false;
        }
        if (type == 1) {
            start = rk.after(startTime) ? rk : startTime;
            end = ck.before(YDateUtils.addDateHours(startTime, 8)) ? ck : YDateUtils.addDateHours(startTime, 8);
        } else if (type == 2) {
            start = rk.after(YDateUtils.addDateHours(startTime, 8)) ? rk : YDateUtils.addDateHours(startTime, 8);
            if (endTime.before(start)) {
                start = endTime;
            }
            end = ck.before(YDateUtils.addDateHours(startTime, 16)) ? ck : YDateUtils.addDateHours(startTime, 16);
            if (endTime.before(end)) {
                end = endTime;
            }
        } else {
            start = rk.after(startTime) ? rk : startTime;
            end = ck.before(endTime) ? ck : endTime;
        }
        workplan.setaPg(workplan.getWorkName() + ":" + String.format("(%d小时%d分)", (end.getTime() - start.getTime()) / 1000 / 60 / 60
                , (end.getTime() - start.getTime()) % (1000 * 60 * 60) / (60 * 100)));
        return true;

    }

    //a评估出入量
    private void addInOutString(CareISBARAPgOutVO careISBARAPgOutVO, IsbarIOOutVo isbarIOOutVo) {
        StringBuilder builder;
        if (null != careISBARAPgOutVO.getaPg()) {
            builder = new StringBuilder(careISBARAPgOutVO.getaPg());
        } else {
            builder = new StringBuilder();
        }
        if (isbarIOOutVo.getInValue().equals("0") || isbarIOOutVo.getInValue().equals("0.0")) {
            builder.append("总入量：").append("0").append("ml;");
        } else {
            builder.append("总入量：").append(isbarIOOutVo.getInValue()).append("ml;");
        }
        addIodWord(isbarIOOutVo.getInList(), builder);
        if (isbarIOOutVo.getOutValue().equals("0") || isbarIOOutVo.getOutValue().equals("0.0")) {
            builder.append("总出量：").append("0").append("ml;");
        } else {
            builder.append("总出量：").append(isbarIOOutVo.getOutValue()).append("ml;");
        }
        addIodWord(isbarIOOutVo.getOutList(), builder);
        careISBARAPgOutVO.setaPg(builder.toString());
    }

    public void addIodWord(List<IoCodeDetailVO> list, StringBuilder builder) {
        if (CollectionUtil.isNotEmpty(list)) {
            for (IoCodeDetailVO item : list) {
                if (!item.getIoValue().equals("0.0") &&
                        !item.getIoValue().equals("0")) {
                    builder.append(item.getItemName()).append(":").append(item.getIoValue()).append("ml");
                }

            }
        }
    }

    public void addListRemindWord(List<IsbarPgRecordDTO> list, StringBuilder operaBuilder, int type) {
        if (CollectionUtil.isNotEmpty(list)) {
            for (IsbarPgRecordDTO item : list) {
                switch (type) {
                    case 0:
                        if (checkGcs(item.getValue())) {
                            addRemindWord(item, operaBuilder);
                            return;
                        }
                        break;
                    case 1:
                        if (checkFall(item.getValue())) {
                            addRemindWord(item, operaBuilder);
                            return;
                        }
                        break;
                    case 2:
                        if (checkBraden(item.getValue())) {
                            addRemindWord(item, operaBuilder);
                            return;
                        }
                        break;
                    case 4:
                        addVteRemindWord(item, operaBuilder);
                        return;
                    default:
                        addRemindWord(item, operaBuilder);
                        return;
                }
            }
        }
    }

    private boolean checkGcs(String resultValue) {
        if (null == resultValue) {
            return false;
        }


        int value1 = -1;
        if (resultValue.contains("(")) {
            resultValue = resultValue.substring(0, resultValue.indexOf("("));
            value1 = Integer.valueOf(resultValue);
        } else {
            value1 = Integer.valueOf(resultValue);
        }
        if (value1 >= 3 && value1 <= 8) {
            return true;
        }
        return false;
    }

    public void addRemindWord(IsbarPgRecordDTO item, StringBuilder operaBuilder) {
        operaBuilder.append(item.getPgName()).append(":").append(item.getValue()).append(";");
    }

    private boolean checkFall(String resultValue) {
        if (null == resultValue) {
            return false;
        }


        int value1 = -1;
        if (resultValue.contains("分")) {
            resultValue = resultValue.substring(0, resultValue.indexOf("分"));
            value1 = Integer.valueOf(resultValue);
        }
        if (value1 > 45) {
            return true;
        }
        if (resultValue.contains("高")) {
            return true;
        }
        return false;
    }


    private boolean checkBraden(String resultValue) {
        if (null == resultValue) {
            return false;
        }

        int value1 = -1;
        if (resultValue.contains("(")) {
            resultValue = resultValue.substring(0, resultValue.indexOf("("));
            value1 = Integer.valueOf(resultValue);
        }
        if (value1 >= 9 && value1 <= 12) {
            return true;
        }
        return false;
    }


    public void addVteRemindWord(IsbarPgRecordDTO item, StringBuilder stringBuilder) {
        stringBuilder.append(item.getPgName()).append(":").append(item.getValue());

        stringBuilder.append(";");
    }


    @Override
    public PageOutputDTO<BCareIsbarHandoverResultVO> queryRecords(CareISBARQueryInVO queryInVO) {
        String startDate;
        String endDate;
        if (queryInVO.getCurrentDate() == null) {
            //默认展示当前日期往前推一个月的
            DateTime currentDate = DateUtil.date();
            startDate = DateUtil.formatDateTime(DateUtil.lastMonth());
            endDate = DateUtil.formatDateTime(currentDate);
        } else {
            //有日期的情况下，只展示当天的
            Date date = new Date(queryInVO.getCurrentDate());
            long receiveStartOfDay = DateUtil.beginOfDay(date).getTime();
            long endOfDay = DateUtil.endOfDay(date).getTime();
            startDate = DateUtil.formatDateTime(DateUtil.date(receiveStartOfDay));
            endDate = DateUtil.formatDateTime(DateUtil.date(endOfDay));
        }

        IPage<BCareIsbarHandover> page = bCareIsbarHandoverMapper.selectPageByTime(startDate, endDate, queryInVO.getPage(), queryInVO.getSize());
        List<BCareIsbarHandover> records = page.getRecords();
        List<BCareIsbarHandoverResultVO> resultList = records.stream().map(this::convertToOutVo).collect(Collectors.toList());

        return new PageOutputDTO<>(page.getTotal(), page.getPages(), page.getCurrent(), resultList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(CareISBARHandoverInVO inVo) {
        Date date = new Date(inVo.getJiaoBanTime());
        long receiveStartOfDay = DateUtil.beginOfDay(date).getTime();
        long endOfDay = DateUtil.endOfDay(date).getTime();
        String startDate = DateUtil.formatDateTime(DateUtil.date(receiveStartOfDay));
        String endDate = DateUtil.formatDateTime(DateUtil.date(endOfDay));
        //加锁 以保证这条数据同时操作时候， 交班数据保持一份
//        RLock lock = redissonClient.getLock(ISBAR_LOCK_PRE + startDate);

        if ( redisDistributedLock.lock(ISBAR_LOCK_PRE + startDate)) {
            try {
                Long id = inVo.getId();
                if (id != null) {
                    BCareIsbarHandover handoverPoById = bCareIsbarHandoverMapper.selectById(id);
                    if (handoverPoById == null) {
                        throw new BizException("数据不存在，请检查");
                    }
                    //先删除后修改
                    delete(id);
                }
                //校验是否重复添加，一天只能加入一条交班记录
                BCareIsbarHandover handoverPoByTime = bCareIsbarHandoverMapper.selectOneByTime(startDate, endDate);
                if (handoverPoByTime != null) {
                    throw new BizException("当前日期已经有交班记录，请勿重复添加");
                }
                //新增
                BCareIsbarHandover newHandoverPo = new BCareIsbarHandover();
                BeanUtil.copyProperties(inVo, newHandoverPo);
                bCareIsbarHandoverMapper.insert(newHandoverPo);
                //插入明细记录
                List<BCareIsbarHandoverDetailSaveVO> detailList = inVo.getDetailList();
                for (BCareIsbarHandoverDetailSaveVO detailOutVO : detailList) {
                    BCareIsbarHandoverDetail detailPo = new BCareIsbarHandoverDetail();
                    BeanUtil.copyProperties(detailOutVO, detailPo);
                    detailPo.setRecordId(newHandoverPo.getId());
                    bCareIsbarHandoverDetailMapper.insert(detailPo);
                    if (CollectionUtil.isNotEmpty(detailOutVO.getJiaoBanList())) {
                        List<BCareIsbarAPg> aPgList = detailOutVO.getJiaoBanList().stream().map(outVO -> {
                            BCareIsbarAPg aPgPo = new BCareIsbarAPg();
                            BeanUtil.copyProperties(outVO, aPgPo);
                            aPgPo.setDetailId(detailPo.getId());
                            return aPgPo;
                        }).collect(Collectors.toList());
                        bCareIsbarAPgService.saveBatch(aPgList);
                    }
                }
            } catch (Exception e) {
                log.error("ISBAR交班数据保存失败, lockKey ={} e = {}", ISBAR_LOCK_PRE + startDate, e.getMessage());
                throw new BizException("数据保存失败 " + e.getMessage());
            } finally {
//                lock.unlock();
                redisDistributedLock.releaseLock(ISBAR_LOCK_PRE + startDate);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        BCareIsbarHandover handoverPo = bCareIsbarHandoverMapper.selectById(id);
        if (handoverPo == null) {
            throw new BizException("数据不存在，请检查");
        }
        Set<Long> detailIdList = bCareIsbarHandoverDetailMapper.selectListByRecordId(id).stream().map(BCareIsbarHandoverDetail::getId).collect(Collectors.toSet());
        bCareIsbarHandoverMapper.deleteById(id);
        bCareIsbarHandoverDetailMapper.deleteByRecordId(id);
        bCareIsbarAPgMapper.deleteByDetailIdList(detailIdList);
    }


    /**
     * ISBAR 获取手术数量
     *
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public Long operaCount(Long startTime, Long endTime) {
        if (null != startTime && null != endTime && endTime < startTime) {
            throw new BizException("开始时间不能大于结束时间");
        }
        Date day = new Date(System.currentTimeMillis());
        Date start;
        Date end;
        if (day.before(YDateUtils.strToDate(YDateUtils.dateToDayStr(day) + " 07:59:59", YDateUtils.DATE_TIME_PATTERN))) {
            start = YDateUtils.stringToDate(YDateUtils.dateToDayStr(YDateUtils.addDateDays(day, -1))
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
            end = YDateUtils.stringToDate(YDateUtils.dateToDayStr(day)
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
        } else {
            start = YDateUtils.stringToDate(YDateUtils.dateToDayStr(day)
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
            end = YDateUtils.stringToDate(YDateUtils.dateToDayStr(YDateUtils.addDateDays(day, 1))
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
        }
        if (null != startTime) {
            start = new Date(startTime);
        }
        if (null != endTime) {
            end = new Date(endTime);
        }
        List<PatientInfoOutVO> yxPatientList = bPatientMapper.selectListByDept(systemProperties.getIcuCode());
        Set<String> hospitalNumSet = yxPatientList.stream().map(PatientInfoOutVO::getHospitalNumber).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
        return bHl7YzMapper.selectOperasByHospNumListAndTypeAndTime(hospitalNumSet, YzTypeEnum.SHOUSHU.getTypeCode(), start, end);
    }

    /**
     * ISBAR 出入量统计
     *
     * @param startTime
     * @param endTime
     * @param hospitalNumber
     * @return
     */
    @Override
    public IsbarIOOutVo inout(String hospitalNumber, Long startTime, Long endTime) {
        if (endTime < startTime) {
            throw new BizException("开始时间不能大于结束时间");
        }
        //入量统计列表
        List<IoCodeDetailVO> listIn = bIoRecordMapper.queryIoStatisticsList("crl-in", hospitalNumber, new Date(startTime), new Date(endTime));
        //出量统计列表
        List<IoCodeDetailVO> listOut = bIoRecordMapper.queryIoStatisticsList("crl-out", hospitalNumber, new Date(startTime), new Date(endTime));
        //总计入量
        List<IoCodeDetailVO> sumIn = bIoRecordMapper.queryIoStatisticsSum("crl-in", hospitalNumber, new Date(startTime), new Date(endTime));
        //总计出量
        List<IoCodeDetailVO> sumOut = bIoRecordMapper.queryIoStatisticsSum("crl-out", hospitalNumber, new Date(startTime), new Date(endTime));
        IsbarIOOutVo isbarIOOutVo = new IsbarIOOutVo();
        isbarIOOutVo.setOutList(listOut);
        isbarIOOutVo.setInList(listIn);
        if (CollectionUtil.isNotEmpty(sumIn)) {
            isbarIOOutVo.setInValue(sumIn.get(0).getIoValue());
        }
        if (null == isbarIOOutVo.getInValue()) {
            isbarIOOutVo.setInValue("0");
        }
        if (CollectionUtil.isNotEmpty(sumOut)) {
            isbarIOOutVo.setOutValue(sumOut.get(0).getIoValue());
        }
        if (null == isbarIOOutVo.getOutValue()) {
            isbarIOOutVo.setOutValue("0");
        }
        isbarIOOutVo.setTime(String.format("%d小时%d分", (endTime - startTime) / 1000 / 60 / 60
                , (endTime - startTime) % (1000 * 60 * 60) / (60 * 100)));
        return isbarIOOutVo;
    }

    @Override
    public List<IsbarPgRecordDTO> remind(String hospitalNumber, Long startTime, Long endTime) {
        if (null != startTime && null != endTime && endTime < startTime) {
            throw new BizException("开始时间不能大于结束时间");
        }
        Date day = new Date(System.currentTimeMillis());
        Date start;
        Date end;
        if (day.before(YDateUtils.strToDate(YDateUtils.dateToDayStr(day) + " 07:59:59", YDateUtils.DATE_TIME_PATTERN))) {
            start = YDateUtils.stringToDate(YDateUtils.dateToDayStr(YDateUtils.addDateDays(day, -1))
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
            end = YDateUtils.stringToDate(YDateUtils.dateToDayStr(day)
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
        } else {
            start = YDateUtils.stringToDate(YDateUtils.dateToDayStr(day)
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
            end = YDateUtils.stringToDate(YDateUtils.dateToDayStr(YDateUtils.addDateDays(day, 1))
                    + " 07:59:59", YDateUtils.DATE_TIME_PATTERN);
        }
        if (null != startTime) {
            start = new Date(startTime);
        }
        if (null != endTime) {
            end = new Date(endTime);
        }
        List<IsbarPgRecordDTO> out = new ArrayList<>();
        //GCS重度昏迷
        List<IsbarPgRecordDTO> list = bPgRecordMapper.getLatestPgRecord("pgpf_glasgow", hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            for (IsbarPgRecordDTO item : list) {
                if (checkGcs(item.getValue())) {
                    out.add(item);
                    break;
                }
            }
        }
        //跌倒/坠床评分
        list = bCarePgVteMapper.getLatestVTEPgRecord(4, hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            for (IsbarPgRecordDTO item : list) {
                if (checkFall(item.getValue())) {
                    out.add(item);
                    break;
                }
            }
        }
        //Braden评分
        list = bPgRecordMapper.getLatestPgRecord("pgpf_braden", hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            for (IsbarPgRecordDTO item : list) {
                if (checkBraden(item.getValue())) {
                    out.add(item);
                    break;
                }
            }
            ;
        }
        //ISS评分
        list = bPgRecordMapper.getLatestPgRecord("pgpf_iss", hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            out.add(list.get(0));
        }
        //APACHII评分
        list = bCarePgVteMapper.getLatestVTEPgRecord(2, hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            out.add(list.get(0));
        }
        //SOFA评分
        list = bPgRecordMapper.getLatestPgRecord("pgpf_sofa", hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            out.add(list.get(0));
        }
        //VTE评分
        list = bCarePgVteMapper.getLatestVTEPgRecord(1, hospitalNumber, start, end);
        if (CollectionUtil.isNotEmpty(list)) {
            out.add(list.get(0));
        }
        return out;
    }


}


